package core

import (
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strings"
	"sync"
	"time"
)

// 接收数据

type ScanResult struct {
	Success bool   `json:"success"` // 正确性
	Err     string `json:"err"`     // 错误信息
	Me      string `json:"me"`      // 自己的身份
	Channel string `json:"channel"` // 频道全大写
}

type IpScanResult struct {
	Ip string
	Me string
}

// 网段扫描 - 全部扫描后统一汇报数据
func ScanCIDR(cidr string, port int, channel string, maxReq int) ([]IpScanResult, error) {
	// 获取网段列表
	iplis, err := RangeCIDR(cidr)
	if err != nil {
		return nil, err
	}
	lenth := len(iplis)
	if lenth == 0 {
		return nil, errors.New("cidr range length is 0")
	}
	// 并发访问
	// maxReq := 15 // 最大并发访问数量
	seg := lenth / maxReq
	if lenth%maxReq > 0 {
		seg++
	}
	wg := sync.WaitGroup{}
	wg.Add(maxReq)
	// 启动子协程,布置请求任务
	mu := sync.Mutex{}
	reslis := make([]IpScanResult, 0) // 结果列表
	for i := 0; i < maxReq; i++ {
		// 计算数据范围
		start := i * seg
		end := (i + 1) * seg
		if end > lenth {
			end = lenth
		}
		// 运行子协程
		go func(ip_part []string, port int, channel string) {
			partlis := make([]IpScanResult, 0)
			// 依次访问所有的ip
			for _, ip := range ip_part {
				sr := ScanOnce(ip, port, channel)
				if sr.Success {
					partlis = append(partlis, IpScanResult{
						Ip: ip,
						Me: sr.Me,
					})
					// 直接输出到控制台
					fmt.Printf("me:%v , ip:%v\n", ip, sr.Me)
				}
			}
			// 汇报数据
			if len(partlis) > 0 {
				mu.Lock()
				defer mu.Unlock()
				reslis = append(reslis, partlis...)
			}
			// 结束本协程
			wg.Done()
		}(iplis[start:end], port, channel)
	}
	// 等待所有子协程运行完毕
	wg.Wait()
	return reslis, nil
}

// 进行1次请求
func ScanOnce(ip string, port int, channel string) *ScanResult {
	sr := &ScanResult{
		Success: false,
		Err:     "None-Err",
		Me:      "None-me",
		Channel: "None-Channel",
	}
	// 组合URL信息
	u := url.URL{}
	u.Scheme = "http"
	u.Host = fmt.Sprintf("%v:%v", ip, port)
	u.Path = "/httpami"
	AmiLoger.Printf("u.String(): %v\n", u.String())
	// 请求开始
	scanUrl := u.String()
	req, err := http.NewRequest("GET", scanUrl, strings.NewReader(channel))
	if err != nil {
		sr.Err = err.Error()
		return sr
	}
	// resp, err := http.DefaultClient.Do(req)
	// http.DefaultClient.Timeout = 30
	client := http.Client{
		Timeout: time.Millisecond * 50, // HTTP的超时时间
	}
	resp, err := client.Do(req)
	if err != nil {
		sr.Err = err.Error()
		return sr
	}
	// 获取Me数据
	data, err := io.ReadAll(resp.Body)
	if err != nil {
		sr.Err = err.Error()
		return sr
	}
	replyMe := string(data)
	AmiLoger.Printf("scan req-reply:[%v]", replyMe)
	if len(replyMe) == 0 {
		sr.Err = "reply-is-empty"
		return sr
	}
	sr.Success = true
	sr.Me = replyMe
	sr.Channel = channel
	return sr
}
